package ai.people.core.webhook.feishu.utils;

import ai.people.core.webhook.entity.ErrorInfo;
import ai.people.core.webhook.feishu.constant.MsgEnum;
import ai.people.core.webhook.feishu.constant.TagEnum;
import ai.people.core.webhook.feishu.msg.CardMsg;
import ai.people.core.webhook.feishu.properties.WebhookInfo;
import ai.people.netmon.utils.NumeralPool;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhenglin
 * @date 2022/5/17
 */
@Component
@EnableConfigurationProperties(WebhookInfo.class)
@ConditionalOnProperty(value = "feishu.webhook.enabled", havingValue = "true")
@RequiredArgsConstructor
@Slf4j
public class FeishuWebhookMsg {

    private final WebhookInfo webhookInfo;

    public boolean send(RestTemplate restTemplate, String title, String msg) {
        CardMsg.Card cardMsg = new CardMsg.Card();

        CardMsg.Card.Header header = new CardMsg.Card.Header();

        CardMsg.Card.Header.Title title1 = new CardMsg.Card.Header.Title();
        title1.setTag(TagEnum.plain_text.name());
        title1.setContent(title);
        header.setTitle(title1);
        header.setTemplate("red");

        cardMsg.setHeader(header);

        List<CardMsg.Card.Elements> elements = new ArrayList<>();
        CardMsg.Card.Elements elements1 = new CardMsg.Card.Elements();
        CardMsg.Card.Elements.Text text = new CardMsg.Card.Elements.Text();
        text.setTag(TagEnum.lark_md.name());
        text.setContent(msg);
        text.setLines(NumeralPool.TWENTY);
        elements1.setText(text);
        elements1.setTag(TagEnum.div.name());

        elements.add(elements1);
        cardMsg.setElements(elements);
        cardMsg.setConfig(new CardMsg.Card.Config());
        return send(restTemplate, cardMsg);
    }

    public boolean send(RestTemplate restTemplate, ErrorInfo errorInfo) {
        CardMsg.Card cardMsg = new CardMsg.Card();

        CardMsg.Card.Header header = new CardMsg.Card.Header();

        CardMsg.Card.Header.Title title1 = new CardMsg.Card.Header.Title();
        title1.setTag(TagEnum.plain_text.name());
        title1.setContent(errorInfo.getErrMsgTitle());
        header.setTitle(title1);
        header.setTemplate("red");
        cardMsg.setHeader(header);

        List<CardMsg.Card.Elements> elements = new ArrayList<>();
        buildCardMsgCardElements(elements, "ip", errorInfo.getRequestIp());
        buildCardMsgCardElements(elements, "url", errorInfo.getRequestUrl());
        buildCardMsgCardElements(elements, "method", errorInfo.getRequestMethod());
        buildCardMsgCardElements(elements, "params", errorInfo.getRequestJson());
        buildCardMsgCardElements(elements, "堆栈信息", errorInfo.getErrStackTrace());


        cardMsg.setElements(elements);
        cardMsg.setConfig(new CardMsg.Card.Config());
        return send(restTemplate, cardMsg);
    }

    private void buildCardMsgCardElements(List<CardMsg.Card.Elements> elements, String lineTitle, String msg) {
        CardMsg.Card.Elements element = new CardMsg.Card.Elements();
        CardMsg.Card.Elements.Text text = new CardMsg.Card.Elements.Text();
        text.setTag(TagEnum.lark_md.name());
        text.setContent("**" + lineTitle + "**\n" + msg);
        text.setLines(NumeralPool.HUNDRED);
        element.setText(text);
        element.setTag(TagEnum.div.name());

        CardMsg.Card.Elements hr = new CardMsg.Card.Elements();
        hr.setTag(TagEnum.hr.name());

        elements.add(element);
        elements.add(hr);
    }


    public boolean send(RestTemplate restTemplate, CardMsg.Card cardMsg) {
        try {
            CardMsg msg = new CardMsg();
            int timestamp = (int) (System.currentTimeMillis() / 1000);
            msg.setTimestamp(timestamp);
            String sign = genSign(webhookInfo.getSecret(), timestamp);
            msg.setSign(sign);
            msg.setCard(cardMsg);
            msg.setMsgType(MsgEnum.interactive.name());
            String json = JSONObject.toJSONString(msg);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> request = new HttpEntity<>(json, headers);
            ResponseEntity<JSONObject> response = restTemplate.postForEntity(webhookInfo.getUrl(), request, JSONObject.class);
            JSONObject jsonObject = response.getBody();
            log.info("send msg to feishu webhook, result:{}", jsonObject);
            Integer statusCode = jsonObject.getInteger("StatusCode");
            if (statusCode == NumeralPool.ZERO) {
                return true;
            } else {
                log.error("发送消息到飞书webhook失败,错误信息:{}", jsonObject);
            }
        } catch (Exception e) {
            log.error("发送消息到飞书webhook失败", e);
        }
        return false;
    }

    /**
     * 创标志
     *
     * @param secret    秘密
     * @param timestamp 时间戳
     * @return {@link String}
     * @throws NoSuchAlgorithmException 没有这样算法异常
     * @throws InvalidKeyException      无效关键例外
     */
    private static String genSign(String secret, int timestamp) throws NoSuchAlgorithmException, InvalidKeyException {
        //把timestamp+"\n"+密钥当做签名字符串
        String stringToSign = timestamp + "\n" + secret;
        //使用HmacSHA256算法计算签名
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] signData = mac.doFinal(new byte[]{});
        return new String(Base64.encodeBase64(signData));
    }
}
